package com.carb.interceptor;

import com.carb.constant.JwtConstant;
import com.carb.context.UserContext;
import com.carb.properties.JwtProperties;
import com.carb.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.List;
import java.util.Map;

/**
 * JWT拦截器
 */
@Slf4j
public abstract class JwtTokenInterceptor implements HandlerInterceptor {

    @Resource
    private JwtProperties jwtProperties;

    /**
     * 抽象方法，用于获取当前用户角色
     * @return 当前用户角色
     */
    protected abstract List<String> getRequiredRole();

    /**
     * 校验jwt
     * @param request 请求
     * @param response 响应
     * @param handler 请求头
     * @return boolean true：通过校验，false：未通过校验
     */
    @Override
    public boolean preHandle(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler) {
        // 1、判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            // 当前拦截到的不是动态方法，直接放行
            return true;
        }

        // 2、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getTokenName());

        // 3、校验令牌
        try {
            log.info("jwt校验: {}", token);
            // 3.1、解析jwt并且获取其中的信息
            Claims claims = JwtUtils.parseJWT(jwtProperties.getSecretKey(), token);
            Long userId = Long.valueOf(claims.get(JwtConstant.USER_ID).toString()); // 用户id
            String role = String.valueOf(claims.get(JwtConstant.ROLE)); // 用户角色
            log.info("当前用户id：{}，当前用户角色：{}，合法角色：{}", userId, role, getRequiredRole());
            if (getRequiredRole().contains(role)) {
                log.info("角色合法，已授权访问！");
                // 3.2、将当前用户userId和role存入ThreadLocal
                UserContext.setUser(Map.of(JwtConstant.USER_ID, userId, JwtConstant.ROLE, role));
                // 3.3、通过，放行
                log.info("jwt校验通过");
                return true;
            } else {
                log.info("角色非法，未授权访问！");
                // 3.4、不通过，响应401状态码
                response.setStatus(401);
                log.error("jwt校验不通过");
                return false;
            }
        } catch (Exception e) {
            // 4、不通过，响应401状态码
            response.setStatus(401);
            log.error("jwt校验失败");
            return false;
        }
    }
}

